#!/bin/sh
#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#@function: restore oracle


restore_controlfile()
{
    log_info "Running RMAN to restore control file"

    instance_name=$1
    db_user=$2
    db_password=$3
    db_name=$4

    tmp_sql="${STMP_PATH}/restore_controlfile_${PID}.sql"
    tmp_rst="${STMP_PATH}/restore_controlfile_${PID}.rst"
    upper_db_name=`echo "${db_name}" | tr '[a-z]' '[A-Z]'`

    echo "startup nomount pfile='${IN_ORACLE_HOME}/dbs/init"${DBINSTANCE}".ora';" > "${tmp_sql}"
    echo "restore controlfile from '$MAIN_BACKUP_PATH/controlfile.ctl';" >> "${tmp_sql}"
    echo "startup mount;" >> "${tmp_sql}"
    echo "configure default device type to disk;" >> "${tmp_sql}"
    echo "crosscheck datafilecopy tag 'EBACKUP-${upper_db_name}-DATA';" >> "${tmp_sql}"
    echo "delete noprompt expired datafilecopy all;" >> "${tmp_sql}"
    echo "delete noprompt expired backupset;" >> "${tmp_sql}"
    echo "crosscheck archivelog all;" >> "${tmp_sql}"
    echo "delete noprompt expired archivelog all;" >> "${tmp_sql}"
    echo "quit;" >> "${tmp_sql}"
    chown "${ORA_DB_USER}" "${tmp_sql}"
    chmod 700 "${tmp_sql}"

    rman_exe_script "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 0
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "Restore ${DBNAME}-${DBINSTANCE} controlfile failed, error=${ret_code}"
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        exit ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}" "true"
    log_info "Restore controlfile ${DBNAME}-${DBINSTANCE} succ."
}

check_dg_exit()
{
    if [ -n "${RECOVERPATH}" ] || [ "$RECOVERTARGET" -ne "1" ]; then
        return 0
    fi
    for line in `cat "$ADDITIONAL"/dbfiles`; do
        dbf_full_path=`echo "$line" | ${MYAWK} -F ";" '{print $4}'`
        if [ "`rd_substr "${dbf_full_path}" 1 1`" != "+" ]; then
            continue
        fi
        dg_name=${dbf_full_path%%/*}
        echo "${dg_list}" | grep "${dg_name}" >/dev/null 2>&1
        if [ $? -ne 0 ]; then
            dg_list="${dg_list} ${dg_name}"
        fi
    done
    for line in `cat "$ADDITIONAL"/ctrlfiles`; do
        dbf_full_path="$line"
        if [ "`rd_substr "${dbf_full_path}" 1 1`" != "+" ]; then
            continue
        fi
        dg_name=${dbf_full_path%%/*}
        echo "${dg_list}" | grep "${dg_name}" >/dev/null 2>&1
        if [ $? -ne 0 ]; then
            dg_list="${dg_list} ${dg_name}"
        fi
    done
    for line in `cat "$ADDITIONAL"/logfiles`; do
        dbf_full_path=`echo "$line" | ${MYAWK} -F ";" '{print $2}'`
        if [ "`rd_substr "${dbf_full_path}" 1 1`" != "+" ]; then
            continue
        fi
        dg_name=${dbf_full_path%%/*}
        echo "${dg_list}" | grep "${dg_name}" >/dev/null 2>&1
        if [ $? -ne 0 ]; then
            dg_list="${dg_list} ${dg_name}"
        fi
    done
    if [ -z "${dg_list}" ]; then
        return 0
    fi
    log_info "Begin check dg list"

    for dg_name in ${dg_list}; do
        dg_name=`rd_substr "${dg_name}" 2`
        set_env_cmd=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
        echo lsdg "${dg_name}" | su - "${ORA_GRID_USER}" "${GRID_SHELL_MODE}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} asmcmd" | grep "${dg_name}"
        if [ $? -ne 0 ]; then
            log_error "Diskgroup ${dg_name} does not exist or is not mounted"
            return "${ERROR_ORACLE_DISKGROUP_NOT_EXIT}"
        fi
    done
}

build_catalog_datafile_sql()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    restote_sql=$4

    datafile_tmp_sql="${STMP_PATH}/list_datafile_copy_${PID}.sql"
    datafile_tmp_rst="${STMP_PATH}/list_datafile_copy_${PID}.txt"

    echo "list datafilecopy all;" > "${datafile_tmp_sql}"
    echo "quit;" >> "${datafile_tmp_sql}"
    chown "${ORA_DB_USER}" "${datafile_tmp_sql}"
    chmod 700 "${datafile_tmp_sql}"

    rman_exe_script "${db_user}" "${db_password}" "${datafile_tmp_sql}" "${datafile_tmp_rst}" "${instance_name}" -1 0
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "List datafilecopy all failed, error=${ret_code}."
        delete_file "${datafile_tmp_sql}" "${datafile_tmp_rst}"
        exit ${ret_code}
    fi
    data_file_path="${STMP_PATH}/data_file_path_${PID}.txt"
    cat "${datafile_tmp_rst}" | grep "/mnt/databackup" > "${data_file_path}"
    delete_file "${datafile_tmp_sql}" "${datafile_tmp_rst}"

    ip_use_info="${STMP_PATH}/ip_use_info_${PID}.txt"
    for data_path in `echo "$BACKUP_PATH_LIST" | sed 's/;/ /g'`; do
        num=`cat "${data_file_path}" | grep -c "${data_path}"`
        echo "${data_path}=${num}" >> "${ip_use_info}"
    done
    for line in `cat "$ADDITIONAL"/dbfiles`; do
        file_id=`echo "${line}" | ${MYAWK} -F ";" '{print $3}'`
        if [ -z "${file_id}" ]; then
            continue
        fi
        cat "${data_file_path}" | grep "/data/${file_id}/FNO"
        if [ $? -ne 0 ]; then
            find_min_use_path
            echo "    catalog start with '${path}/${file_id}' noprompt;" >> "${restote_sql}"
        fi
    done
    delete_file "${data_file_path}" "${ip_use_info}"
}

find_min_use_path()
{
    num=0
    tmp_txt="${STMP_PATH}/tmp_txt_${PID}"
    for line in `cat "${ip_use_info}"`; do
        if [ "${num}" -eq 0 ]; then
            path=`echo "${line}" | ${MYAWK} -F "=" '{print $1}'`
            num=`echo "${line}" | ${MYAWK} -F "=" '{print $2}'`
        else
            if [ "${num}" -gt "`echo "${line}" | ${MYAWK} -F "=" '{print $2}'`" ]; then
                path=`echo "${line}" | ${MYAWK} -F "=" '{print $1}'`
                num=`echo "${line}" | ${MYAWK} -F "=" '{print $2}'`
            fi
        fi
    done
    num=`expr "${num}" + 1`
    grep -v "${path}" "${ip_use_info}" > "${tmp_txt}"
    cat "${tmp_txt}" > "${ip_use_info}"
    echo "${path}=${num}" >> "${ip_use_info}"
    delete_file "${tmp_txt}"
}

build_original_restore_database_sql()
{
    
    instance_name=$1
    db_user=$2
    db_password=$3
    tmp_sql=$4
    
    echo "RESET DATABASE TO INCARNATION ${INCAR_NUM};" > "${tmp_sql}"
    echo "RUN" >> "${tmp_sql}"
    echo "{" >> "${tmp_sql}"
    index=1
    while [ "$index" -le "$CHANNELS" ]; do
        echo "    allocate channel eRestore`printf "%02d" "$index"` type disk;" >> "${tmp_sql}"
        index=`expr "$index" + 1`
    done
    echo "    configure device type disk parallelism $CHANNELS;" >> "${tmp_sql}"
    # 全量副本全部catalog
    echo "    catalog start with '$MAIN_BACKUP_PATH/' noprompt;" >> "${tmp_sql}"
    # 兼容老日志副本结构
    if [ -d "${ARCHIVE}/resetlogs_id${RESETLOGS_ID}" ];then
        log_info "Start catalog archive log, ${ARCHIVE}/resetlogs_id${RESETLOGS_ID}."
        echo "    catalog start with '${ARCHIVE}/resetlogs_id${RESETLOGS_ID}' noprompt;" >> "${tmp_sql}"
    fi
    log_info "Start catalog archive log, log joblist :${JOBID_LIST}."
    JOBID_LIST=`echo "$JOBID_LIST" | sed 's/,/ /g' `
    if [ -z "${JOBID_LIST}" ] && [ -n "${ARCHIVE}" ]; then
        log_warn "JOBID_LIST is none"
        echo "    catalog start with '${ARCHIVE}' noprompt;" >> "${tmp_sql}"
    else
      for job_id in ${JOBID_LIST}; do
        echo "    catalog start with '${ARCHIVE}/${job_id}/resetlogs_id${RESETLOGS_ID}' noprompt;" >> "${tmp_sql}"
      done
    fi

    # ADG从库任意时间点恢复进入此分支
    # ADG从库直接使用时间点恢复会失败，故先使用数据副本的scn恢复，再使用时间点恢复
    if [ "${DATABASE_ROLE}" != "PRIMARY" ] && [ "$PIT_SCN" = "0" ];then
        echo "    RESTORE DATABASE;" >> "${tmp_sql}"
        scn_dbf_max=`cat "${ADDITIONAL}"/scn_dbf_max | ${MYAWK} '{print $1}'`
        echo "    RECOVER DATABASE until scn ${scn_dbf_max};" >> "${tmp_sql}"
        echo "    RECOVER DATABASE until ${PIT} ;" >> "${tmp_sql}"
    else
        echo "    restore database;" >> "${tmp_sql}"
        echo "    recover database until $PIT;" >> "${tmp_sql}"
    fi

    index=1
    while [ "$index" -le "$CHANNELS" ]; do
        echo "    release channel eRestore`printf "%02d" "$index"`;" >> "${tmp_sql}"
        index=`expr "$index" + 1`
    done
    echo "}" >> "${tmp_sql}"

}

checkbct_and_open_db()
{
    # disable CBT
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/get_controlfile_path_list${PID}.sql"
    tmp_rst="${STMP_PATH}/get_controlfile_path_list${PID}.rst"

    echo "startup mount;" > "${tmp_sql}"
    echo "select status from v\$block_change_tracking;" >> "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"
    BCT_STATUS="DISABLED"
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1 
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        log_warn "Query cbt status failed, ret=$ret_code, error is `cat "$tmp_rst"`"
    else
        BCT_STATUS="` sed -n '$p' "$tmp_rst" `"
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"

    if [ "${BCT_STATUS}" = "DISABLED" ]; then
        echo "ALTER DATABASE OPEN RESETLOGS;" > "${tmp_sql}"
    else
        echo "alter database disable BLOCK CHANGE TRACKING;" > "${tmp_sql}"
        echo "ALTER DATABASE OPEN RESETLOGS;" >> "${tmp_sql}"
    fi
    set_db_silence_sql "${tmp_sql}"
    # open resetlogs
    log_info "Begin to open database resetlogs, BCT_STATUS=$BCT_STATUS."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ];then
        log_error "Open resetlogs database-${instance_name} failed, error=${ret_code}"
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        return ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}" "true"
    log_info "Open resetlogs database-${instance_name} succ."
}

create_dirs_from_file()
{
    file_name=$1
    log_info "Creating dirs from file ($1)."
    tmp_txt="${STMP_PATH}/create_dirs_from_file${PID}.txt"
    $MYAWK 'BEGIN{FS="/"; OFS="/"}{$NF=""; print}' "$file_name" | $MYAWK -F ";" '{print $NF}' | sort -u > "$tmp_txt"
    for line in `cat "${tmp_txt}"`; do
        create_dir "$line"
    done
    delete_file "$tmp_txt"
}

delete_expired_archivelog()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/get_controlfile_path_list${PID}.sql"
    tmp_rst="${STMP_PATH}/get_controlfile_path_list${PID}.rst"

    echo "crosscheck archivelog all;" > "${tmp_sql}"
    echo "delete noprompt expired archivelog all;" >> "${tmp_sql}"
    echo "delete noprompt archivelog like '${ARCHIVE}/%';" >> "${tmp_sql}"
    db_mount_pt="${MAIN_BACKUP_PATH%/*}"
    echo "delete noprompt archivelog like '${db_mount_pt%/*}/%';" >> "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    chown "${ORA_DB_USER}" "${tmp_sql}"
    chmod 700 "${tmp_sql}"

    rman_exe_script "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 0
    ret_code=$?
    if [ ${ret_code} -ne 0 ]; then
        log_error "Delete expired archivelog failed ret=${ret_code}"
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        return $ret_code
    fi
    log_info "Delete expired archivelog success."
    delete_file "${tmp_sql}" "${tmp_rst}" "true"
}

create_db_config_dir()
{
    # restriction
    # 1. asm instance       ASMSIDNAME
    log_info "Begin to prepare DB env"
    pfile_path=$1
    db_name=$2

    # create adump direcory
    adump_dir=`cat "${pfile_path}" | grep audit_file_dest | ${MYAWK} -F"'" '{print $2}'`
    create_dir "${adump_dir}"
    
    # create diag rdbms directory
    diag_dir=`cat "${pfile_path}" | grep diagnostic_dest | ${MYAWK} -F"'" '{print $2}'`
    create_dir "${diag_dir}"

    # create archive dest
    recover_dest=`cat "${pfile_path}" | grep db_recovery_file_dest= | ${MYAWK} -F"'" '{print $2}'`
    if [ -z "${recover_dest}" ]; then
        return
    fi
    create_dir "${recover_dest}"
    # create archive dest  and   set owner
    db_name=`echo "$db_name"| tr 'a-z' 'A-Z'`
    recover_dest="${recover_dest}/${db_name}"
    create_dir "${recover_dest}"
}

replace_pfile_env_by_newenv()
{
    # 1. pfile              PFILE_NAME

    log_info "Begin to replace oracle home and oracle base env value"

    backup_ora_base_path=`grep "ORACLE_BASE=" "$ADDITIONAL/env_file" | sed -n "1p" | $MYAWK -F= '{print $2}'`
    backup_ora_home_path=`grep "ORACLE_HOME=" "$ADDITIONAL/env_file" | sed -n "1p" | $MYAWK -F= '{print $2}'`


    # replace oracle home path
    sed "s#${backup_ora_home_path}#${IN_ORACLE_HOME}#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak 2>>"$LOG_FILE_NAME"
    if [ $? -ne 0 ]; then
        log_error "Replace pfile oracle home path failed" 
        return "$ERROR_BACKUP_INVALID"
    fi
    mv "${PFILE_NAME}".bak "${PFILE_NAME}" >>"$LOG_FILE_NAME" 2>&1
    if [ $? -ne 0 ]; then
        log_error "Replace pfile oracle home path failed" 
        return "$ERROR_BACKUP_INVALID"
    fi

    # replace oracle base path
    sed "s#${backup_ora_base_path}#${IN_ORACLE_BASE}#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak 2>>"$LOG_FILE_NAME" 
    if [ $? -ne 0 ]; then
        log_error "Replace pfile oracle base path failed" 
        return "$ERROR_BACKUP_INVALID"
    fi
    mv "${PFILE_NAME}".bak "${PFILE_NAME}" >>"$LOG_FILE_NAME" 2>&1
    if [ $? -ne 0 ]; then
        log_error "Replace pfile oracle base path failed" 
        return "$ERROR_BACKUP_INVALID"
    fi
}

create_spfile_from_pfile()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    spfile_location=$4
    
    if [ -z "${spfile_location}" ]; then
        tmp_str=`cat "$ADDITIONAL"/spfile`
        spfile_location=${tmp_str%/*}
        if [ -z "${spfile_location}" ]; then
            log_warn "Spfile location path is none, Copy database may login using pfile"
            spfile_location="${IN_ORACLE_HOME}/dbs"
        fi
        create_dir "${spfile_location}"
    fi
    lowercase_db_name=`echo "${DBNAME}" | tr 'A-Z' 'a-z'`

    if [ -f "${spfile_location}/ebackup-spfile${lowercase_db_name}.ora" ]; then
        log_warn "Location already has the same name spfile [${spfile_location}/ebackup-spfile${lowercase_db_name}.ora] will delete."
        delete_file "${spfile_location}/ebackup-spfile${lowercase_db_name}.ora"
    fi
    log_info "Begin to create spfile to location [${spfile_location}]."

    tmp_sql="${STMP_PATH}/create_spfile_from_pfile${PID}.sql"
    tmp_rst="${STMP_PATH}/create_spfile_from_pfile${PID}.rst"

    echo "STARTUP NOMOUNT PFILE='${PFILE_NAME}';" > "${tmp_sql}"
    echo "CREATE SPFILE='${spfile_location}/ebackup-spfile${lowercase_db_name}.ora' FROM PFILE='${PFILE_NAME}';" >> "${tmp_sql}"
    echo "SHUTDOWN ABORT;" >> "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        log_error "Create spfile failed, ret=$ret_code, msg `cat "${tmp_rst}"`."
        delete_file "${tmp_sql}" "${tmp_rst}"
        exit ${ret_code}
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"
    log_info "Create spfile [${spfile_location}/ebackup-spfile${lowercase_db_name}.ora] succ."
}

# replace control file list in pfile using backup path
modify_pfile_config_param()
{
    dst_file_path=$1
    OMF_ENABLE=0
    
    omf_dest=`grep -i "db_create_file_dest" "${PFILE_NAME}" | $MYAWK -F "#" '{print $1}' |$MYAWK -F "=" '{print $2}'`
    omf_dest=${omf_dest#*\'}
    omf_dest=${omf_dest%*\'}
    upper_db_name=`echo "${DBNAME}" | tr '[a-z]' '[A-Z]'`
    if [ -n "$omf_dest" ]; then
        OMF_ENABLE=1
        create_dir "${dst_file_path}/${upper_db_name}/datafile"
    fi 

    # Modify *.control_files
    if [ -n "${dst_file_path}" ]; then
        if [ "$OMF_ENABLE" -eq 1 ]; then 
            create_dir "${dst_file_path}/${upper_db_name}/controlfile/"
            control_file="\'${dst_file_path}/${upper_db_name}/controlfile/controlfile.ctl\'"
        else
            control_file="\'${dst_file_path}/controlfile.ctl\'"
        fi
        grep ".CONTROL_FILES=" "${PFILE_NAME}"
        if [ $? -eq 0 ]; then
            sed "s#^\(.*\)\(CONTROL_FILES=.*\)#\1control_files=${control_file}#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
        else
            sed "s#^\(.*\)\(control_files=.*\)#\1control_files=${control_file}#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
        fi
        mv "${PFILE_NAME}".bak "${PFILE_NAME}"
    else
        control_file_dest_list=`grep -i "control_files" "${PFILE_NAME}" | $MYAWK -F "#" '{print $1}' | $MYAWK -F "=" '{print $2}' | sed "s#,# #g"`
        for control_file_item in ${control_file_dest_list}; do
            control_file_item=${control_file_item#*\'}
            control_file_item=${control_file_item%*\'}
            create_dir "${control_file_item%/*}"
        done
    fi

    # Modify *.db_create_file_dest
    if [ "$OMF_ENABLE" -eq 1 ] && [ -n "$dst_file_path" ]; then
        grep ".DB_CREATE_FILE_DEST=" "${PFILE_NAME}"
        if [ $? -eq 0 ]; then
            sed "s#^\(.*\)\(DB_CREATE_FILE_DEST=.*\)#\1db_create_file_dest=${dst_file_path}#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
        else
            sed "s#^\(.*\)\(db_create_file_dest=.*\)#\1db_create_file_dest=${dst_file_path}#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
        fi
        mv "${PFILE_NAME}".bak "${PFILE_NAME}"
    elif [ "$OMF_ENABLE" -eq 1 ] && [ -z "$dst_file_path" ]; then
        create_dir "${omf_dest}"
    fi

    # Modify *.log_archive_dest_n
    archived_dest_list=`grep -i "log_archive_dest" "${PFILE_NAME}"`
    for archived_dest_item in ${archived_dest_list}; do
        log_archive_dest=`echo "${archived_dest_item}" | $MYAWK -F "#" '{print $1}' | $MYAWK -F "=" '{print $1}'`
        log_archive_dest=${log_archive_dest#*.}
        archived_dest_item=`echo "${archived_dest_item}" | $MYAWK -F "#" '{print $1}' | $MYAWK -F "${log_archive_dest}=" '{print $2}'`
        echo "$archived_dest_item" | grep "="
        if [ $? -eq 0 ]; then
            archived_dest_item=${archived_dest_item#*\'}
            archived_dest_item=${archived_dest_item%*\'}
            archived_dest_item=`echo "${archived_dest_item}" | $MYAWK -F "=" '{print $2}'`
            if [ -n "${archived_dest_item}" ] && [ -n "$dst_file_path" ]; then
                sed "s#^\(.*\)\(${log_archive_dest}=.*\)#\1${log_archive_dest}='LOCATION=${dst_file_path}'#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
                mv "${PFILE_NAME}".bak "${PFILE_NAME}"
                break
            fi
        else
            if [ -n "${archived_dest_item}" ] && [ -n "$dst_file_path" ]; then
                sed "s#^\(.*\)\(${log_archive_dest}=.*\)#\1${log_archive_dest}='${dst_file_path}'#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
                mv "${PFILE_NAME}".bak "${PFILE_NAME}"
                break
            fi
        fi

        if [ -n "${archived_dest_item}" ]; then
            create_dir "${archived_dest_item}"
        fi
    done
    # Modify *.db_recovery_file_dest
    fast_recover_dest=`grep -i "db_recovery_file_dest=" "${PFILE_NAME}" | $MYAWK -F "=" '{print $2}'`
    fast_recover_dest=${fast_recover_dest#*\'}
    fast_recover_dest=${fast_recover_dest%*\'}
    if [ -n "${fast_recover_dest}" ]; then
        if [ -n "${fast_recover_dest}" ] && [ -n "$dst_file_path" ]; then
            grep ".DB_RECOVERY_FILE_DEST=" "${PFILE_NAME}"
            if [ $? -eq 0 ]; then
                sed "s#^\(.*\)\(DB_RECOVERY_FILE_DEST=.*\)#\1db_recovery_file_dest='${dst_file_path}'#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
            else
                sed "s#^\(.*\)\(db_recovery_file_dest=.*\)#\1db_recovery_file_dest='${dst_file_path}'#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
            fi 
            mv "${PFILE_NAME}".bak "${PFILE_NAME}"
        elif [ -n "${fast_recover_dest}" ]; then
            create_dir "${fast_recover_dest}"
        fi
    fi

    # RAC to Single-Instance
    if [ 0 -eq "${DBISCLUSTER}" ] || [ 2 -eq "${DBISCLUSTER}" ]; then
        grep ".CLUSTER_DATABASE" "${PFILE_NAME}"
        if [ $? -eq 0 ]; then
            sed "s#^\(.*\)\(CLUSTER_DATABASE.*\)#\1cluster_database=FALSE#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
        else
            sed "s#^\(.*\)\(cluster_database.*\)#\1cluster_database=FALSE#g" "${PFILE_NAME}" > "${PFILE_NAME}".bak
        fi 
        
        mv "${PFILE_NAME}".bak "${PFILE_NAME}"
    fi
    chown -h "${ORA_DB_USER}":"${ORA_DB_GROUP}" "${PFILE_NAME}"
}

build_catalog_sql()
{
    tmp_sql=$1
    echo "    catalog start with '$MAIN_BACKUP_PATH/' noprompt;" >> "${tmp_sql}"
    # 兼容老日志副本结构
    if [ -d "${ARCHIVE}/resetlogs_id${RESETLOGS_ID}" ];then
      log_info "Start catalog archive log, ${ARCHIVE}/resetlogs_id${RESETLOGS_ID}."
      echo "    catalog start with '${ARCHIVE}/resetlogs_id${RESETLOGS_ID}' noprompt;" >> "${tmp_sql}"
    fi
    JOBID_LIST=`echo "${JOBID_LIST}" | sed 's/,/ /g'`
    if [ -z "${JOBID_LIST}" ] && [ -n "${ARCHIVE}" ]; then
        log_warn "JOBID_LIST is none"
        echo "    catalog start with '${ARCHIVE}' noprompt;" >> "${tmp_sql}"
    else
      for job_id in ${JOBID_LIST}; do
        echo "    catalog start with '${ARCHIVE}/${job_id}/resetlogs_id${RESETLOGS_ID}' noprompt;" >> "${tmp_sql}"
      done
    fi
}

build_newname_datafile_sql()
{   
    tmp_sql=$1
    upper_db_name=`echo "${DBNAME}" | tr '[a-z]' '[A-Z]'`
    target_path=
    if [ "${TASK_TYPE}" -eq 0 ] && [ -n "${RECOVERPATH}" ]; then
        target_path=${RECOVERPATH}
    fi
    if [ "${TASK_TYPE}" -eq 1 ] || [ "${TASK_TYPE}" -eq 2 ]; then
        target_path=`echo "${BACKUP_PATH_LIST}" | $MYAWK -F ";" '{print $1}'`
    fi
    if [ -z "${target_path}" ]; then
        return
    fi
    line=
    for line in `cat "$ADDITIONAL"/dbfiles`; do
        tablespace_name=`echo "${line}" | ${MYAWK} -F ";" '{print $2}'`
        file_iD=`echo "${line}" | ${MYAWK} -F ";" '{print $3}'`
        if [ "${TASK_TYPE}" -eq 0 ] && [ -n "${RECOVERPATH}" ]; then
            if [ "$OMF_ENABLE" -eq 0 ]; then 
                echo "    SET NEWNAME FOR DATAFILE ${file_iD} to '${target_path}/FNO-${file_iD}_TS-${tablespace_name}.dbf';" >> "${tmp_sql}"
            else
                create_dir "${target_path}/${upper_db_name}/datafile"
                echo "    SET NEWNAME FOR DATAFILE ${file_iD} to '${target_path}/${upper_db_name}/datafile/FNO-${file_iD}_TS-${tablespace_name}.dbf';" >> "${tmp_sql}"
            fi
        else
            echo "    SET NEWNAME FOR DATAFILE ${file_iD} to '${target_path}/${file_iD}/FNO-${file_iD}_TS-${tablespace_name}.dbf';" >> "${tmp_sql}"
        fi
    done
}

build_rename_datafile_sql()
{
    tmp_sql=$1
    target_path=
    if [ "${TASK_TYPE}" -eq 0 ] && [ -n "${RECOVERPATH}" ]; then
        target_path="${RECOVERPATH}"
    fi
    if [ "${TASK_TYPE}" -eq 1 ] || [ "${TASK_TYPE}" -eq 2 ]; then
        target_path=`echo "${BACKUP_PATH_LIST}" | $MYAWK -F ";" '{print $1}'`
    fi
    if [ -z "${target_path}" ]; then
        return
    fi
    line=
    upper_db_name=`echo "${DBNAME}" | tr '[a-z]' '[A-Z]'`
    if [ "${ORA_PREVERSION}" -gt 11 ]; then
        for line in `cat "$ADDITIONAL"/dbfiles`; do
            tablespace_name=`echo "${line}" | ${MYAWK} -F ";" '{print $2}'`
            fileID=`echo "${line}" | ${MYAWK} -F ";" '{print $3}'`
            src_path=`echo "${line}" | $MYAWK -F ";" '{print $4}'`
            if [ "${TASK_TYPE}" -eq 0 ] && [ -n "${RECOVERPATH}" ]; then
                if [ "$OMF_ENABLE" -eq 0 ]; then 
                    target_name="${target_path}/FNO-${fileID}_TS-${tablespace_name}.dbf"
                else
                    target_name="${target_path}/${upper_db_name}/datafile/FNO-${fileID}_TS-${tablespace_name}.dbf"
                fi
            else
                target_name="${target_path}/${fileID}/FNO-${fileID}_TS-${tablespace_name}.dbf"
            fi
            prefix="+"
            if [[ $target_name == $prefix* ]]; then
              log_info "target_name start with +"
              # asm磁盘路径，忽略大小写
              upper_src_path=`echo "${src_path}" | tr '[a-z]' '[A-Z]'`
              upper_target_name=`echo "${target_name}" | tr '[a-z]' '[A-Z]'`
              if [ "${upper_src_path}" != "${upper_target_name}" ]; then
                echo "    ALTER DATABASE RENAME FILE '${src_path}' to '${target_name}';" >> "${tmp_sql}"
              fi
            else
              if [ "${src_path}" != "${target_name}" ]; then
                echo "    ALTER DATABASE RENAME FILE '${src_path}' to '${target_name}';" >> "${tmp_sql}"
              fi
            fi
        done
        echo "    SWITCH DATAFILE ALL;" >> "${tmp_sql}"
    else
        echo "    SWITCH DATAFILE ALL;" >> "${tmp_sql}"
    fi
    
}

get_db_role()
{
    db_role_tmp_sql="${STMP_PATH}/database_role_${PID}.sql"
    db_role_tmp_rst="${STMP_PATH}/database_role_${PID}.rst"
    echo "select database_role from v\$database;" > "${db_role_tmp_sql}"
    echo "exit;" >> "${db_role_tmp_sql}"
    set_db_silence_sql "${db_role_tmp_sql}"
    oracle_exe_sql "${db_user}" "${db_password}" "${db_role_tmp_sql}" "${db_role_tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    if [ $ret_code -ne 0 ]; then
        log_error "Query database role failed, ret=$ret_code, error is `cat "${db_role_tmp_rst}"`"
        delete_file "${db_role_tmp_sql}" "${db_role_tmp_rst}"
        return $ret_code
    fi
    DATABASE_ROLE="`cat "${db_role_tmp_rst}"`"
    log_info "Database role:${DATABASE_ROLE}."
    delete_file "${db_role_tmp_sql}" "${db_role_tmp_rst}"
    echo "${DATABASE_ROLE}"
}

build_rename_log_file_for_standby()
{
    log_info "Start build rename redo log file sql."
    tmp_redo_sql_file=$1
    exec_by_rman=$2

    tmp_rst="${STMP_PATH}/get_online_log_info_rst_${PID}.txt"
    get_online_redo_log_info "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" "${tmp_rst}"
    if [ $? -ne 0 ]; then
        log_error "Get database online log file info failed."
        delete_file "${tmp_rst}"
        exit "${RETURN_INVALID}"
    fi
    if [ "${DATABASE_ROLE}" != "PRIMARY" ];then
      if [ "${exec_by_rman}" = "rman" ]; then
         echo "sql \"alter system set standby_file_management=''MANUAL''\";" >> "${tmp_redo_sql_file}"
      else
          echo "alter system set standby_file_management='MANUAL';" >> "${tmp_redo_sql_file}"
      fi
    fi
    TimeStamp=`date +%s`
    counter=0
    line=
    while read line; do
        # 依次处理每一个redo名称
        [ -z "$line" ] && continue
        redo_file=`echo "$line" | $MYAWK '{print $2}'`
        #
        if [ -n "${RECOVERPATH}" ]; then
            # 指定恢复路径
            upper_db_name=`echo "${DBNAME}" | tr '[a-z]' '[A-Z]'`
            # 开启OMF则构造路径
            if [ "$OMF_ENABLE" -eq 1 ]; then
                temp_path="${RECOVERPATH}/${upper_db_name}"
            fi
            src_path=`echo "${line}" | $MYAWK '{print $2}'`
            if [ "$OMF_ENABLE" -eq 1 ];then
                create_dir "$temp_path/onlinelog"
                dst_path="${temp_path}/onlinelog/restore-redo-${counter}"
            else
                dst_path="${RECOVERPATH}/restore-redo-${counter}"
            fi
            echo "     ALTER DATABASE RENAME FILE '${src_path}' to '${dst_path}-${TimeStamp}';" >> "${tmp_redo_sql_file}"
        else
            # 不指定恢复路径,直接在原目录下新增
            redo_file_path="${redo_file%/*}/"
            echo "     ALTER DATABASE RENAME FILE '${redo_file}' to '${redo_file_path}-${TimeStamp}';" >> "${tmp_redo_sql_file}"
        fi
        counter=$((counter+1))
    done < "$tmp_rst"
    delete_file "${tmp_rst}"
}

clear_redo_log_file()
{
    log_info "Start clear redo log file."
    tmp_redo_sql_file="${STMP_PATH}/clear_redo_log_file_${PID}.sql"
    clear_redo_log_file_rst="${STMP_PATH}/clear_redo_log_file_rst_${PID}.rst"
    tmp_rst="${STMP_PATH}/get_online_log_info_rst_${PID}.txt"
    get_online_redo_log_info "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" "${tmp_rst}"
    if [ $? -ne 0 ]; then
        log_error "Get database online log file info failed."
        delete_file "${tmp_rst}"
        exit "${RETURN_INVALID}"
    fi

    line=
    while read line; do
        # 依次处理每一个redo名称
        [ -z "$line" ] && continue
        redo_group=`echo "$line" | $MYAWK '{print $1}'`
        log_info "ALTER DATABASE CLEAR LOGFILE group ${redo_group};"
        echo "ALTER DATABASE CLEAR LOGFILE group ${redo_group};" >> "${tmp_redo_sql_file}"
    done < "$tmp_rst"
    echo "exit;" >> "${tmp_redo_sql_file}"
    delete_file "${tmp_rst}"

  chown "${ORA_DB_USER}" "${tmp_redo_sql_file}"
  chmod 700 "${tmp_redo_sql_file}"
  oracle_exe_sql "${DBUSER}" "${DBUSERPWD}" "${tmp_redo_sql_file}" "${clear_redo_log_file_rst}" "${DBINSTANCE}" 600 1
  ret_code=$?
  if [ ${ret_code} -ne 0 ];then
      log_error "Clear database-${DBINSTANCE} redo log file failed, ret=${ret_code}"
      delete_file "${tmp_redo_sql_file}" "${clear_redo_log_file_rst}" "true"
      exit ${ret_code}
  fi
  delete_file "${tmp_redo_sql_file}" "${clear_redo_log_file_rst}" "true"
  log_info "Clear database-${DBINSTANCE} redo log file successfully."
}

build_rename_log_file()
{
    tmp_sql=$1
    line=
    TimeStamp=`date +%s`
    upper_db_name=`echo "${DBNAME}" | tr '[a-z]' '[A-Z]'`
    if [ "$OMF_ENABLE" -eq 1 ]; then
        temp_path="${RECOVERPATH}/${upper_db_name}"
    fi
    rename_counter=0
    for line in `cat "$ADDITIONAL"/logfiles`; do
        src_path=`echo "${line}" | $MYAWK -F ";" '{print $2}'`
        if [ "$OMF_ENABLE" -eq 1 ];then
            create_dir "$temp_path/onlinelog"
            dst_path="${temp_path}/onlinelog/restore-redo-${rename_counter}"
        else
            dst_path="${RECOVERPATH}/restore-redo-${rename_counter}"
        fi
        [ "${src_path}" = "${dst_path}" ]  && continue
            
        grep "${src_path}" "${tmp_sql}"
        if [ $? -ne 0 ]; then
            echo "    ALTER DATABASE RENAME FILE '${src_path}' to '${dst_path}-${TimeStamp}';" >> "${tmp_sql}"
        fi
        rename_counter=$((rename_counter+1))
    done
}

build_db_restore_rman_script()
{
    tmp_sql=$1

    channel_name=
    if [ "$TASK_TYPE" -eq 0 ]; then
        channel_name="eRestore"
    elif [ "$TASK_TYPE" -eq 1 ]; then 
        PIT="scn `cat "${ADDITIONAL}"/scn_dbf_max | ${MYAWK} '{print $1}'`"
        channel_name="eLivemount"
    elif [ "$TASK_TYPE" -eq 2 ]; then
        channel_name="eInsrestore"
    fi
    log_info "Begin to exec DB restore taskType ${channel_name} to ${PIT}, IS_ENC_BK is ${IS_ENC_BK}."
    echo "RESET DATABASE TO INCARNATION ${INCAR_NUM};" > "${tmp_sql}"
    echo "RUN" >> "${tmp_sql}"
    echo "{" >> "${tmp_sql}"
    echo "    SET COMMAND ID TO 'ProtectAgent_Restore';" >> "${tmp_sql}"
    index=1
    while [ "$index" -le "$CHANNELS" ]; do
        echo "    allocate channel ${channel_name}`printf "%02d" "$index"` type disk;" >> "${tmp_sql}"
        index=`expr "$index" + 1`
    done
    if [ "${DATABASE_ROLE}" != "PRIMARY" ];then
        echo "sql \"alter system set standby_file_management=''MANUAL''\";" >> "${tmp_sql}"
    fi
    build_catalog_sql "${tmp_sql}"
    build_newname_datafile_sql "${tmp_sql}"
    if [ "${ORA_PREVERSION}" -gt 11 ] && [ -n "${RECOVERPATH}" ]; then
        if [ "${DATABASE_ROLE}" != "PRIMARY" ];then
            build_rename_log_file_for_standby "${tmp_sql}" "rman"
        else
            build_rename_log_file "${tmp_sql}"
        fi
    fi

    # ADG从库任意时间点恢复进入此分支
    # ADG从库直接使用时间点恢复会失败，故先使用数据副本的scn恢复，再使用时间点恢复
    if [ "${DATABASE_ROLE}" != "PRIMARY" ] && [ "$PIT_SCN" = "0" ];then
        echo "    RESTORE DATABASE;" >> "${tmp_sql}"
        build_rename_datafile_sql "${tmp_sql}"
        scn_dbf_max=`cat "${ADDITIONAL}"/scn_dbf_max | ${MYAWK} '{print $1}'`
        echo "    RECOVER DATABASE until scn ${scn_dbf_max};" >> "${tmp_sql}"
        echo "    RECOVER DATABASE until ${PIT} ;" >> "${tmp_sql}"
    else
        echo "    SET UNTIL ${PIT};" >> "${tmp_sql}"
        echo "    RESTORE DATABASE;" >> "${tmp_sql}"
        build_rename_datafile_sql "${tmp_sql}"
        echo "    RECOVER DATABASE;" >> "${tmp_sql}"
    fi

    #新位置恢复指定目标位置时处理临时文件
    if [ "$RECOVERTARGET" -eq 2 ] && [ -n "${RECOVERPATH}" ]; then
        build_rename_temp_file_sql "${tmp_sql}"
    fi

    index=1
    while [ "$index" -le "$CHANNELS" ]; do
        echo "    release channel ${channel_name}`printf "%02d" "$index"`;" >> "${tmp_sql}"
        index=`expr "$index" + 1`
    done
    echo "}" >> "${tmp_sql}"
}

create_init_file()
{
    spfile_location=$1
    lower_case_dbname=`echo "${DBNAME}" | tr 'A-Z' 'a-z'`

    if [ -z "${spfile_location}" ]; then
        tmp_str=`cat "$ADDITIONAL"/spfile`
        spfile_location=${tmp_str%/*}
        if [ -z "${spfile_location}" ]; then
            log_warn "Spfile location path is none"
            spfile_location="${IN_ORACLE_HOME}/dbs"
        fi
    fi
    if [ "`rd_substr "${spfile_location}" 1 1`" = "/" ]; then
        if [ ! -f "${spfile_location}/ebackup-spfile${lower_case_dbname}.ora" ]; then
            log_error "Spfile [${spfile_location}] location is none or spfile is not exit cant not creaet init file"
            exit "${RETURN_INVALID}"
        fi
    else
        check_path_in_disk_group "${spfile_location}" "${ASMSIDNAME}"
        if [ $? -ne 0 ]; then
            log_error "Spfile [${spfile_location}] location is none or spfile is not exit cant not creaet init file"
            exit "${RETURN_INVALID}"
        fi
    fi
    
    log_info "Begin to create oracle init file init${DBINSTANCE}.ora, SpfileLocation is ${spfile_location}."
    
    su - "$ORA_DB_USER" -c "${EXPORT_ORACLE_ENV} rm -f ${IN_ORACLE_HOME}/dbs/init${DBINSTANCE}.ora" >> "${LOG_FILE_NAME}" 2>&1
    su - "$ORA_DB_USER" -c "${EXPORT_ORACLE_ENV} touch ${IN_ORACLE_HOME}/dbs/init${DBINSTANCE}.ora" >> "${LOG_FILE_NAME}" 2>&1
    su - "$ORA_DB_USER" -c "${EXPORT_ORACLE_ENV} echo \"SPFILE='"${spfile_location}"/ebackup-spfile"${lower_case_dbname}".ora'\" > ${IN_ORACLE_HOME}/dbs/init${DBINSTANCE}.ora" >> "${LOG_FILE_NAME}" 2>&1
    if [ $? -ne 0 ]; then
        log_error "Create ${DBINSTANCE} init file error"
        exit "${RETURN_INVALID}"
    fi
}

create_pfile_from_pm()
{
    if [ -z "${PFILEPID}" ]; then
        backup_pfile=${MAIN_BACKUP_PATH}/ebackup-$DBNAME-pfile.ora
        if [ ! -f "$backup_pfile" ]; then
            log_error "Copy path pfile [ $backup_pfile ] is not exist can not retore"
            exit "$RETURN_INVALID"
        fi
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} cp -d -f ${backup_pfile} ${PFILE_NAME}" >> "${LOG_FILE_NAME}" 2>&1
        if [ $? -ne 0 ]; then
            log_error "Copy path pfile to oracle home failed can not retore"
            exit "$RETURN_INVALID"
        fi 
        log_info "Copy pfile from ${backup_pfile} to ${PFILE_NAME} success"
    else
        user_pfile="${TMP_PATH}/pfile${PFILEPID}"
        if [ ! -f "${user_pfile}" ]; then 
            log_error "From pm pfile [$user_pfile] is not exit can not restore "
            exit "$RETURN_INVALID"
        fi
        log_info "Create pfile from user pfile pfile${PFILEPID}"
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} rm -rf ${PFILE_NAME}" >> "${LOG_FILE_NAME}" 2>&1
        \cp -d -f "${user_pfile}" "${PFILE_NAME}" && chown -h "${ORA_DB_USER}":"${ORA_DB_GROUP}" "${PFILE_NAME}" >> "${LOG_FILE_NAME}" 2>&1
        if [ $? -ne 0 ]; then
            log_error "Create pfile from user pfile fail "
            exit "$RETURN_INVALID"
        fi
        log_info "Create pfile from user pfile success "
        delete_file "$user_pfile"
    fi
}

disable_database_bct()
{
    instance_name=$1
    db_user=$2
    db_password=$3
    IS_START_DB=$4

    tmp_sql="${STMP_PATH}/disable_bct_${PID}.sql"
    tmp_rst="${STMP_PATH}/disable_bct_${PID}.rst"

    echo "select status from v\$block_change_tracking;" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    if [ $ret_code -ne 0 ]; then
        log_info "Bct status is open before restore."
        BCT_STATUS="ENABLED"
    else
        BCT_STATUS="`cat "${tmp_rst}"`"
    fi
    delete_file "${tmp_sql}" "${tmp_rst}"

    # 获取当前数据库的角色
    tmp_sql="${STMP_PATH}/database_role_${PID}.sql"
    tmp_rst="${STMP_PATH}/database_role_${PID}.rst"
    echo "select database_role from v\$database;" > "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
    ret_code=$?
    if [ $ret_code -ne 0 ]; then
        log_error "Query database role failed, ret=$ret_code, error is `cat "${tmp_rst}"`"
        delete_file "${tmp_sql}" "${tmp_rst}"
        return $ret_code
    fi
    DATABASE_ROLE="`cat "${tmp_rst}"`"
    delete_file "${tmp_sql}" "${tmp_rst}"

    log_info "Begin to open database, DATABASE_ROLE=$DATABASE_ROLE."

    if [ "${BCT_STATUS}" != "DISABLED" ]; then
        echo "alter database disable BLOCK CHANGE TRACKING;" > "${tmp_sql}"
    fi
    if [ "${IS_START_DB}" != "0" ]; then
        if [ "${UPGRADE}" -eq 1 ]; then
            echo "ALTER DATABASE OPEN RESETLOGS UPGRADE;" >> "${tmp_sql}"
        else
           if [ "$DATABASE_ROLE" != "PRIMARY" ]; then
              echo "ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;" >> "${tmp_sql}"
              echo "ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;" >> "${tmp_sql}"
              echo "alter database open;" >> "${tmp_sql}"
            else
                echo "ALTER DATABASE OPEN RESETLOGS;" >> "${tmp_sql}"
            fi
        fi
    fi
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    log_info "Begin to open database resetlogs, BCT_STATUS=$BCT_STATUS."
    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ];then
        log_error "Open resetlogs database-${DBINSTANCE} failed, error=${ret_code}"
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        exit ${ret_code}
    else
        if [ "${IS_START_DB}" != "0" ]; then
            log_info "Open resetlogs database-${DBINSTANCE} succ."
        else
            log_info "No need to open resetlogs database-${DBINSTANCE}, disable BCT succ."
        fi
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
    fi
}

enable_bct_after_restore()
{
    db_user=$1
    db_password=$2
    instance_name=$3
    bct_status=$4

    log_info "Enable bct start!"
    if [ "${bct_status}" = "true" ]; then
        tmp_sql="${STMP_PATH}/temp_enable_bct_${PID}.sql"
        tmp_rst="${STMP_PATH}/temp_enable_bct_${PID}.rst"
        TimeStamp=`date +%s`
        # 指定恢复路径
        omf_dest=`grep -i "db_create_file_dest" "${PFILE_NAME}" | $MYAWK -F "#" '{print $1}' |$MYAWK -F "=" '{print $2}'`
        omf_dest=${omf_dest#*\'}
        omf_dest=${omf_dest%*\'}
        if [ -n "$omf_dest" ]; then
            OMF_ENABLE=1
        fi
        # 开启OMF则构造路径
        if [ "$OMF_ENABLE" -eq 1 ]; then
            echo "alter database enable BLOCK CHANGE TRACKING;" > "${tmp_sql}"
        else
            if [ -n "${RECOVERPATH}" ]; then
                dst_path="${RECOVERPATH}/ctf"
            else
                file_name="$ADDITIONAL/logfiles"
                data=$($MYAWK 'BEGIN{FS="/"; OFS="/"}{$NF=""; print}' "$file_name" | $MYAWK -F ";" '{print $NF}')
                origin_path=$(echo "$data" | head -n 1)
                create_dir "$origin_path"
                # 格式：/oracle/app/oradata/ORCL/
                dst_path="${origin_path}ctf"
                log_info "dst_path:$dst_path"
            fi
            echo "alter database enable BLOCK CHANGE TRACKING using file '${dst_path}-${TimeStamp}.log' reuse;" > "${tmp_sql}"
        fi
        echo "exit;" >> "${tmp_sql}"

        set_db_silence_sql "${tmp_sql}"
        oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" 600 1
        ret_code=$?
        if [ $ret_code -ne 0 ]; then
            log_error "Enable bct failed, ret=$ret_code, error is `cat "${tmp_rst}"`"
            delete_file "${tmp_sql}" "${tmp_rst}"
            return $ret_code
        fi
        delete_file "${tmp_sql}" "${tmp_rst}"
        log_info "Enable bct success, ret=${ret}."
    fi
}

oracle_upgrade()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    tmp_sql="${STMP_PATH}/upgrade_sql${PID}.sql"
    tmp_rst="${STMP_PATH}/upgrade_sql${PID}.rst"
    upgrade_rst="${STMP_PATH}/upgrade_rst_${PID}.txt"

    if [ "${ORACLE_IS_CDB}" -eq 0 ]; then
        echo "ALTER PLUGGABLE DATABASE ALL OPEN UPGRADE FORCE;" > "${tmp_sql}"
        echo "exit;" >> "${tmp_sql}"
        set_db_silence_sql "${tmp_sql}"

        oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
        ret_code=$?
        if [ ${ret_code} -ne 0 ];then
            log_error "Open upgrade pdb database-${DBINSTANCE} failed, error=${ret_code}"
            delete_file "${tmp_sql}" "${tmp_rst}" "true"
            exit ${ret_code}
        fi
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        log_info "Open upgrade pdb database-${DBINSTANCE} success."
    fi
    if [ "${ORA_PREVERSION}"  -gt 11 ]; then
        set_env_cmd=`generate_export_oracle_sid "${DBINSTANCE}"`
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} ${set_env_cmd} cd \$ORACLE_HOME/rdbms/admin; \$ORACLE_HOME/perl/bin/perl catctl.pl -n 4 catupgrd.sql" >> "${upgrade_rst}" 2>&1
        ret_code=$?
        if [ $ret_code -ne 0 ]; then
            log_error "Upgrade database ${DBINSTANCE} failed, error is `cat "${upgrade_rst}"`"
            delete_file "${upgrade_rst}"
            exit $ret_code
        fi
    else 
        echo "spool catupgrade.log" > "${tmp_sql}"
        echo "@?/rdbms/admin/catupgrd.sql" >> "${tmp_sql}"
        echo "exit;" >> "${tmp_sql}"
        set_db_silence_sql "${tmp_sql}"

        oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
        ret_code=$?
        if [ ${ret_code} -ne 0 ]; then
            log_error "Upgrade database-${DBINSTANCE} failed, error=${ret_code}"
            delete_file "${tmp_sql}" "${tmp_rst}" "true"
        fi
    fi
    echo "startup" > "${tmp_sql}"
    echo "@?/rdbms/admin/utlrp.sql" >> "${tmp_sql}"
    echo "exit;" >> "${tmp_sql}"
    set_db_silence_sql "${tmp_sql}"

    oracle_exe_sql "${db_user}" "${db_password}" "${tmp_sql}" "${tmp_rst}" "${instance_name}" -1 1
    ret_code=$?
    if [ ${ret_code} -ne 0 ] && [ ${ret_code} -ne 31 ];then
        log_error "Check upgrade database-${DBINSTANCE} failed, error=${ret_code}"
        delete_file "${tmp_sql}" "${tmp_rst}" "true"
        exit ${ret_code}
    fi

    delete_file "${tmp_sql}" "${tmp_rst}" "true"
    shut_down_db "${instance_name}" "${db_user}" "${db_password}"
    start_open "${instance_name}" "${db_user}" "${db_password}"
    log_info "Upgrade database-${DBINSTANCE} succ."
}

set_rac_pwd_file()
{
    # SPFILE='+DATA/PASS/PWDorarc01'
    # +DATA/PASS/PWDorarc01
    SPFILE_LOCATION_NEW=`echo $SPFILE_LOCATION | ${MYAWK} -F "=" '{print $2}' | tr -d '"' | tr -d "'"`
    dg_name=${SPFILE_LOCATION_NEW%%/*}
    dst_pwd_path="${dg_name}/${DBNAME}/PASSWORD/pwd${DBNAME}"
    set_env_cmd=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
    su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} echo rm -rf  ${dst_pwd_path} | asmcmd" >> "${LOG_FILE_NAME}" 2>&1
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} srvctl modify database -db ${DBNAME} -pwfile ''" >> "${LOG_FILE_NAME}" 2>&1
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} orapwd input_file='${DBPW_FILE}' file='${dst_pwd_path}' dbuniquename='${DBNAME}'" >> "${LOG_FILE_NAME}" 2>&1
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} srvctl modify database -db ${DBNAME} -pwfile '${dst_pwd_path}'" >> "${LOG_FILE_NAME}" 2>&1
}

set_rac_pwd_file_livemount()
{
    #示例 /mnt/4478287e670a428d8ef588ee0bb4f33c/pwdorcl
    dst_pwd_path="${RECOVERPATH}/pwd${DBNAME}"
    log_info "SPFILE_LOCATION_NEW dst_pwd_path is $dst_pwd_path"
    set_env_cmd=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
    su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} echo rm -rf  ${dst_pwd_path} | asmcmd" >> "${LOG_FILE_NAME}" 2>&1
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} srvctl modify database -db ${DBNAME} -pwfile ''" >> "${LOG_FILE_NAME}" 2>&1
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} orapwd input_file='${DBPW_FILE}' file='${dst_pwd_path}'" >> "${LOG_FILE_NAME}" 2>&1
    su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} srvctl modify database -db ${DBNAME} -pwfile '${dst_pwd_path}'" >> "${LOG_FILE_NAME}" 2>&1
}

clear_password_file_config()
{
    # asm系统数据库认证的恢复场景，如果口令文件Password file有值，且同用户名副本的密码与目标主机的密码不同，但是实例名相同，此时会报错，需要如下处理
    #目前看密码文件使用顺序应该是
    #1、srvctl 下先去查询你要拉起的实例，如果实例已经存在并配置了口令文件就使用该实例对应的口令文件
    #2、srvctl 下如果有配置口令文件，但是没有对应要拉起的实例，就使用$ORACLE_HOME/dbs 下的
    #3、srvctl 下如果没有配置口令文件，就使用$ORACLE_HOME/dbs 下的
    instance_name=$1
    log_info "Begin to clear password file, instance name: ${instance_name}"
    generate_tmp_file="${STMP_PATH}/get_db_name_info_tmp_${PID}.txt"
    srvctl_tmp_file="${STMP_PATH}/get_srvctl_config_info_tmp_${PID}.txt"
    if [ "${ORACLE_SHELLTYPE}" = "csh" ]; then
        set_env_cmd="setenv LANG=c;"
    else
        set_env_cmd="export LANG=c;"
    fi
    su - "${ORA_DB_USER}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${set_env_cmd} srvctl config database" > "${generate_tmp_file}" 2>&1
    delete_oracle_mark "${generate_tmp_file}"
    while read line; do
        tmp_db_name=`echo "$line"`
        su - "${ORA_DB_USER}" -c "echo \"${ORACLE_MARK}\"; ${EXPORT_ORACLE_ENV} ${set_env_cmd} srvctl config database -d ${tmp_db_name}" > "${srvctl_tmp_file}" 2>&1
        delete_oracle_mark "${srvctl_tmp_file}"
        db_pwfile=`cat "${srvctl_tmp_file}" | grep "Password file" | $MYAWK -F ":" '{print $2}' | $MYAWK '{gsub(/^\s+|\s+$/, "");print}'`
        log_info "Result of srvctl config database db_pwfile:${db_pwfile},tmp_db_name:${tmp_db_name}"
        if [ -z "${db_pwfile}" ]; then
            continue
        fi
        database_instance=`cat "${srvctl_tmp_file}" | grep "Database instance" | $MYAWK -F ":" '{print $2}' | $MYAWK '{gsub(/^\s+|\s+$/, "");print}'`
        log_info "Result of srvctl config database, db_instance: ${database_instance}."
        database_instance_array=`echo $database_instance | tr ',' '\n'`
        # 遍历数组并打印每个元素
        echo "$database_instance_array" | while IFS= read -r element; do
            log_info "Element(instance name) in srvctl config: ${element}"
            if [ "$instance_name" = "$element" ];then
                log_info "Clear password file."
                su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} srvctl modify database -db ${tmp_db_name} -pwfile ''" >> "${LOG_FILE_NAME}" 2>&1
                break
            fi
        done
    done < "${generate_tmp_file}"
    delete_file "${generate_tmp_file}"
    delete_file "${srvctl_tmp_file}"
}


delete_spfile()
{
    instance_name=$1

    File=`find "${IN_ORACLE_HOME}"/dbs -name "spfile${instance_name}.ora"`
    if [ -n "${File}" ]; then
        log_info "Start delete spfile ${File}"
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} rm -rf ${File}"
        if [ ${?} -ne 0 ]; then
            log_info "Rname Spfile fail"
        fi
    else
        log_info "No Find spfile."
    fi
}

move_log_file()
{
    instance_name=$1
    db_user=$2
    db_password=$3

    log_info "Move log file start"
    MoveOnlineLogSQL="${STMP_PATH}/MoveOnlineLog${PID}.sql"
    MoveOnlineLogRST="${STMP_PATH}/MoveOnlineRST${PID}.txt"
    
    echo "startup mount" > "$MoveOnlineLogSQL"
    get_db_role
    if [ "${DATABASE_ROLE}" != "PRIMARY" ];then
      echo "alter system set standby_file_management='MANUAL';" >> "${MoveOnlineLogSQL}"
    fi
    move_log_counter=0
    for log_file in `cat "${ADDITIONAL}"/logfiles`; do
        log_file=`echo "$log_file" | ${MYAWK} -F ";" '{print $NF}'`
        log_num=`echo "$log_file" | ${MYAWK} -F ";" '{print $1}'`
        create_dir "${log_file%/*}"
        logname=`echo "$log_file" | ${MYAWK} -F "/" '{print $NF}'`
        [ -f "$log_file" ] && rm -rf "$log_file" >> "${LOG_FILE_NAME}" 2>&1
        for line in `cat "${ADDITIONAL}"/livemount/logfiles`; do
            line=`echo "$line" | ${MYAWK} -F ";" '{print $NF}'`
            line_num=`echo "$line" | ${MYAWK} -F ";" '{print $1}'`
            TimeStamp=`date +%s`
            if [ "$line_num" -eq "$log_num" ]; then
                if [ -n "$RECOVERPATH" ]; then
                    log_file_dest="$RECOVERPATH/$logname"
                else
                    log_file_dest=$log_file
                fi
                if [ "`rd_substr "${log_file_dest}" 1 1`" = "/"  ]; then
                    cp -d -f "$line" "$log_file_dest" >> "${LOG_FILE_NAME}" 2>&1
                    chown -h "${ORA_DB_USER}":"${ORA_DB_GROUP}" "${log_file_dest}"
                    echo "ALTER DATABASE RENAME FILE '${line}' to '$log_file_dest';" >> "$MoveOnlineLogSQL"
                else
                    log_file_dest="${$log_file_dest%/*}/restore-redo-${move_log_counter}"
                    set_env_cmd=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
                    su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${set_env_cmd} echo cp $line $log_file_dest-${TimeStamp} | asmcmd" >> "${LOG_FILE_NAME}" 2>& 1
                    echo "ALTER DATABASE RENAME FILE '${line}' to '$log_file_dest-${TimeStamp}';" >> "$MoveOnlineLogSQL"
                    move_log_counter=$((move_log_counter+1))
                fi
                break
            fi
        done
    done
    echo "alter database open ;" >> "$MoveOnlineLogSQL"
    echo "exit;" >> "$MoveOnlineLogSQL"
    chown "${ORA_DB_USER}" "${MoveOnlineLogSQL}"
    chmod 700 "${MoveOnlineLogSQL}"

    oracle_exe_sql "${db_user}" "${db_password}" "${MoveOnlineLogSQL}" "${MoveOnlineLogRST}" "${instance_name}" -1 1
    ret_code=$?
    if [ "$ret_code" -ne "0" ]; then
        log_error "Move log Online failed, ret=$ret_code"
        delete_file "${MoveOnlineLogSQL}" "${MoveOnlineLogRST}" "true"
        exit ${ret_code}
    fi
    delete_file "${MoveOnlineLogSQL}" "${MoveOnlineLogRST}" "true"
    log_info "Move log file end."
}

check_file_restore_path_exist()
{
    file_path=$1

    str_set_env=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
    if [ -n "${file_path}" ]; then
        # check restore path exist
        if [ "`rd_substr "${file_path}" 1 1`" = "/" ]; then
            if [ ! -d "${file_path}" ]; then
                log_error "Recover path:${file_path} is not exist can not restore "
                exit "$ERROR_ORACLE_RECOVERPATH_NOT_EXIT"
            fi
        else
            su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${str_set_env} asmcmd ls ${file_path}"
            if [ ${?} -ne 0 ]; then
                log_error "Recover path:${file_path} is not exist can not restore "
                exit "$ERROR_ORACLE_RECOVERPATH_NOT_EXIT"
            fi
        fi
    fi
}

copy_restore_file()
{
    backup_file=$1
    dest_file=$2
    file_type=$3

    str_set_env=`generate_export_grid_oracle_sid "${ASMSIDNAME}"`
    if [ "`rd_substr "${dest_file}" 1 1`" = "/"  ]; then
        su - "${ORA_DB_USER}" "${ORACLE_SHELL_MODE}" -c "${EXPORT_ORACLE_ENV} cp -d -f ${backup_file} ${dest_file}" >> "${LOG_FILE_NAME}" 2>&1
    else
        su - "${ORA_GRID_USER}" -c "${EXPORT_GRID_ENV} ${str_set_env} echo cp ${backup_file} ${dest_file} | asmcmd" >> "${LOG_FILE_NAME}" 2>& 1
    fi
    if [ $? -ne 0 ]; then
        log_error "Copy backup ${file_type} file from ${backup_file} to ${dest_file} fail "
        exit "$ERROR_ORACLE_FILE_RESTORE_COPY_FAILED"
    fi
    log_info "Copy backup ${file_type} file from ${backup_file} to ${dest_file} success "
}

build_rename_temp_file_sql()
{
    log_info "Start build rename temp file sql."
    tmp_sql=$1
    get_temp_file_rst="${STMP_PATH}/get_temp_file_info_rst_${PID}.txt"
    get_temp_file_info "${DBINSTANCE}" "${DBUSER}" "${DBUSERPWD}" "${get_temp_file_rst}"
    if [ $? -ne 0 ]; then
        log_error "Get database temp file info failed."
        delete_file "${get_temp_file_rst}"
        exit "${RETURN_INVALID}"
    fi
    TimeStamp=`date +%s`
    counter=1
    line=
    while read line; do
        # 依次处理每一个临时文件名称
        [ -z "$line" ] && continue
        # 指定恢复路径
        upper_db_name=`echo "${DBNAME}" | tr '[a-z]' '[A-Z]'`
        # 开启OMF则构造路径
        if [ "$OMF_ENABLE" -eq 1 ]; then
            temp_path="${RECOVERPATH}/${upper_db_name}"
            create_dir "$temp_path/tempfile"
            dst_path="${temp_path}/tempfile/temp-${counter}"
        else
            dst_path="${RECOVERPATH}/temp-${counter}"
        fi
        if [ "${ORA_PREVERSION}" -gt 11 ]; then
            src_path=`echo "${line}" | $MYAWK '{print $2}'`
            echo "    ALTER DATABASE RENAME FILE '${src_path}' to '${dst_path}-${TimeStamp}.dbf';" >> "${tmp_sql}"
        else
            file_id=`echo "${line}" | $MYAWK '{print $1}'`
            echo "    SET NEWNAME FOR TEMPFILE ${file_id} to '${dst_path}-${TimeStamp}.dbf';" >> "${tmp_sql}"
        fi
        counter=$((counter+1))
    done < "$get_temp_file_rst"
    if [ "${ORA_PREVERSION}" -le 11 ]; then
        echo "    SWITCH TEMPFILE ALL;" >> "${tmp_sql}"
    fi
    delete_file "${get_temp_file_rst}"
}
